/*------------------------------------------------------------------------
|                            FILE DESCRIPTION                            |
------------------------------------------------------------------------*/
/*------------------------------------------------------------------------
|  - File name     : os_port.C
|  - Author        : zeweni
|  - Update date   : 2021.03.25
|  - Copyright(C)  : 2021-2021 zeweni. All rights reserved.
------------------------------------------------------------------------*/
/*------------------------------------------------------------------------
|                            COPYRIGHT NOTICE                            |
------------------------------------------------------------------------*/
/*
 * Copyright (C) 2021, zeweni (17870070675@163.com)

 * This file is part of Ant Real Time Operating System.

 * Ant Real Time Operating System is free software: you can redistribute 
 * it and/or modify it under the terms of the Apache-2.0 License.
 
 * Ant Real Time Operating System is distributed in the hope that it will 
 * be useful,but WITHOUT ANY WARRANTY; without even the implied warranty 
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * Apache-2.0 License License for more details.
 
 * You should have received a copy of the Apache-2.0 License.Ant Real Time
 * Operating System. If not, see <http://www.apache.org/licenses/>.
**/
/*------------------------------------------------------------------------
|                                INCLUDES                                |
------------------------------------------------------------------------*/

#include "os_cpu.h"
#include "os_thread.h"
#include "os_core.h"

/*------------------------------------------------------------------------
|                                  DATA                                  |
------------------------------------------------------------------------*/

/**
 * @brief   临界区上锁次数计数器。
 * @details A counter for the number of times the critical section is locked.
 * @note    存放在data区，读写速度最快。
**/
os_uint8_t data G_LockCnt = 0; 


/**
 * @brief   正在运行的线程节点.
 * @details The thread node that is running.
**/
extern OS_Thread_t *G_OS_Thread_RunNode;

/**
 * @brief     线程就绪链表。
 * @details   Thread ready linked list.
**/
extern struct OS_Thread_List G_OS_Thread_RdyList;


/**
  * @name    G_OS_Stack
  * @brief   RTOS kernel stack.
***/
extern struct OS_Kernel_Stk volatile idata Kernel_Stack;


/**
 * @brief   RTOS access external RAM pointer.
**/
extern os_uint8_t xdata *data G_pXRAMStk; 

/**
 * @brief   RTOS accesses the internal RAM pointer..
**/
extern os_uint8_t idata *data G_pRAMStk; 


/*------------------------------------------------------------------------
|                              API FUNCTIONS                             |
------------------------------------------------------------------------*/

/**
 * @brief    拷贝核心堆栈(RAM)到线程堆栈(XRAM)。
 * @details  Copy the core stack (RAM) to the thread stack (XRAM).
**/
#define COPY_STACK_TO_XRAM()                                        \
do{                                                                 \
	G_pXRAMStk = (*G_OS_Thread_RunNode)->StkAddr;                   \
	G_pRAMStk = Kernel_Stack.Block;                                 \
	Kernel_Stack.Length = SP - (os_uint8_t)Kernel_Stack.Block - 1;  \
	*G_pXRAMStk = Kernel_Stack.Length;                              \
	if (G_pXRAMStk[0] > (*G_OS_Thread_RunNode)->StkSize)            \
	{                                                               \
		OS_Exce_Handle(EXC_CODE_STACK_OVER_FLOW);                   \
	}		                                                        \
	while (Kernel_Stack.Length--)                                   \
	{                                                               \
		*(++G_pXRAMStk) = *(++G_pRAMStk);                           \
	}                                                               \
}while(0)


/**
 * @brief    拷贝线程堆栈(XRAM)到核心堆栈(RAM)。
 * @details  Copy the thread stack (XRAM) to the core stack (RAM).
**/
#define COPY_XRAM_TO_STACK()                                        \
do{                                                                 \
	G_pXRAMStk = (*G_OS_Thread_RunNode)->StkAddr;                   \
	G_pRAMStk = Kernel_Stack.Block;                                 \
	Kernel_Stack.Length = G_pXRAMStk[0];                            \
	while (Kernel_Stack.Length--)                                   \
	{                                                               \
		*(++G_pRAMStk) = *(++G_pXRAMStk);                           \
	}                                                               \
	SP = (os_uint8_t)(G_pRAMStk);                                   \
}while(0)


/**
 * @brief     获取就绪线程队列链表中优先级最高的线程。
 * @details   Get the thread with the highest priority in the ready thread list.
 * @param[in] maxPriLabel 最高优先级的线程标号。The thread label with the highest priority.
 * @return    [OS_Thread_t]  更新成功,返回最高优先级的地址。 Update completed.
 * @return    [OS_NULL] 更新失败或者就绪线程链表为空。
 *            The update failed or the ready thread list is empty.
**/
extern OS_Thread_t OS_RdyList_Get_MaxPrio(os_uint8_t *maxPriLabel);

/**
 * @brief   替换就绪链表上的元素。
 * @details Replaces an element on the ready list.
 * @param   index1 要被替换的元素1的数组下标。The array index of the element 1 to be replaced.
 * @param   index2 元素2的数组下标。The index of an array with element 2.
 * @return  None.
**/
extern void OS_RdyList_Replace(os_uint8_t index1,os_uint8_t index2);

/**
 * @brief     更新线程链表。
 * @details   Update the thread list.
 * @param     list 链表地址。Linked list address.
 * @return    None.
**/
extern void OS_Update_List(OS_Thread_t *list);

/**
 * @brief   OS异常处理函数。
 * @details OS exception handling function.
 * @param   excCode 异常代号.Exception code.
 * @return  None.
 * @note    OS运行出现差错时，回调这个异常处理函数，用来指示出现的错误。
 *          When there is an error in the OS operation, 
 *          this exception handling function is called back to indicate the error.
**/
extern void OS_Exce_Handle(os_uint8_t excCode);

/**
 * @brief   OS初始化系统调度器，选择最高优先级的任务执行。
 * @details OS starts system scheduling and selects 
 *          the highest priority task for execution.
 * @param   None.
 * @retval  None.
**/
void OS_Scheduler_Init(void)
{	
	os_uint8_t maxPriLabel = 0;

	G_OS_Thread_RunNode = (OS_Thread_t *)OS_RdyList_Get_MaxPrio(&maxPriLabel);

    OS_RdyList_Replace(maxPriLabel,--G_OS_Thread_RdyList.Num);

	(*G_OS_Thread_RunNode)->Status = OS_THREAD_RUNNING;

	COPY_XRAM_TO_STACK();
	
    __asm POP AR3
    __asm POP AR2
    __asm POP AR1
    __asm POP AR7
    __asm POP AR6
    __asm POP AR5
    __asm POP AR4
    __asm POP AR0
    __asm POP PSW
    __asm POP DPL
    __asm POP DPH
    __asm POP B
    __asm POP ACC
	
	OS_EXIT_CRITICAL();
}


/**
 * @brief   RTOS Context Schedule.
 * @param   None
 * @retval  None
**/
void OS_Thread_Schedule(void)
{
	os_uint8_t maxPriLabel;
	
	OS_ENTER_CRITICAL();
	if (G_OS_Thread_RunNode != OS_NULL)
	{
		__asm PUSH  ACC
		__asm PUSH  B
		__asm PUSH  DPH
		__asm PUSH  DPL
		__asm PUSH  PSW
		__asm PUSH  AR0
		__asm PUSH  AR4
		__asm PUSH  AR5
		__asm PUSH  AR6
		__asm PUSH  AR7
		__asm PUSH  AR1
		__asm PUSH  AR2
		__asm PUSH  AR3
		__asm PUSH  SP
		
		COPY_STACK_TO_XRAM();
		OS_Update_List(G_OS_Thread_RunNode);
	}
	
	G_OS_Thread_RunNode = (OS_Thread_t *)OS_RdyList_Get_MaxPrio(&maxPriLabel);

	(*G_OS_Thread_RunNode)->Status = OS_THREAD_RUNNING;
	
	OS_RdyList_Replace(maxPriLabel,--G_OS_Thread_RdyList.Num);

	COPY_XRAM_TO_STACK();
	
    __asm POP AR3
    __asm POP AR2
    __asm POP AR1
    __asm POP AR7
    __asm POP AR6
    __asm POP AR5
    __asm POP AR4
    __asm POP AR0
    __asm POP PSW
    __asm POP DPL
    __asm POP DPH
    __asm POP B
    __asm POP ACC

    OS_EXIT_CRITICAL();
}


/*------------------------------------------------------------------------
|                    END OF FLIE.  (C) COPYRIGHT zeweni                  |
------------------------------------------------------------------------*/
